package fi.foyt.cs.persistence.dao.user;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import com.beoui.geocell.GeocellManager;
import com.beoui.geocell.model.GeocellQuery;
import com.beoui.geocell.model.Point;

import fi.foyt.cs.persistence.dao.GenericDAO;
import fi.foyt.cs.persistence.domainmodel.user.UserLocation;

public class UserLocationDAO extends GenericDAO<UserLocation> {
  
  public UserLocation create(Long userId, Double latitude, Double longitude) {
    EntityManager entityManager = getEntityManager();
    
    List<String> geocells = GeocellManager.generateGeoCell(new Point(latitude, longitude));

    entityManager.getTransaction().begin();
    try {
      UserLocation userIdentifier = new UserLocation();
      userIdentifier.setGeocells(geocells);
      userIdentifier.setLatitude(latitude);
      userIdentifier.setLongitude(longitude);
      userIdentifier.setUpdated(System.currentTimeMillis());
      userIdentifier.setUserId(userId);
      entityManager.persist(userIdentifier);
      entityManager.getTransaction().commit();
      return userIdentifier;
    } finally {
      if (entityManager.getTransaction().isActive())
        entityManager.getTransaction().rollback();
    }
  }

  public UserLocation findByUserId(Long userId) {
    EntityManager entityManager = getEntityManager();
    Query query = entityManager.createQuery("select u from UserLocation u where userId = :userId");
    query.setParameter("userId", userId);
    return getSingleResult(query);
  }

  public UserLocation update(UserLocation userLocation, Double latitude, Double longitude) {
    EntityManager entityManager = getEntityManager();    

    List<String> geocells = GeocellManager.generateGeoCell(new Point(latitude, longitude));

    entityManager.getTransaction().begin();
    try {
      userLocation.setLatitude(latitude);
      userLocation.setLongitude(longitude);
      userLocation.setGeocells(geocells);
      userLocation.setUpdated(System.currentTimeMillis());
      userLocation = entityManager.merge(userLocation);
      entityManager.getTransaction().commit();

      return userLocation;
    } finally {
      if (entityManager.getTransaction().isActive())
        entityManager.getTransaction().rollback();
    }
  }
  
  public List<UserLocation> listByMaxDistanceAndLastUpdated(Double lat, Double lng, Double maxDistance, Long updated, int maxResults) {
    EntityManager entityManager = getEntityManager();

    Point center = new Point(lat, lng);
    List<Object> params = new ArrayList<Object>();
    params.add(updated);
    GeocellQuery baseQuery = new GeocellQuery("select ul from UserLocation ul");

    return GeocellManager.proximitySearch(center, maxResults, maxDistance, UserLocation.class, baseQuery, entityManager);
  }

}
